
#ifndef TCLIB_H
#define TCLIB_H

#define TCLIB

//tclib : defines minimal C/C++ runtime environment for tcrt based programs.

//require the application to provide an assert handler
extern void assert_msg_handler(const char* test, const char* msg, const char* file, int lineno);
#ifdef _DEBUG
#define assert(cond, msg) if(!(cond)) { assert_msg_handler(#cond, msg, __FILE__, __LINE__); __debugbreak(); }
#else
#define assert(const, msg)
#endif

#define NULL 0

namespace tstd
{
	template <typename T> inline const T& max(const T& a, const T& b) { return (a > b) ? a : b; }
	template<class T> inline const T& min(const T& a, const T& b) { return a < b ? a : b; }
};

//C-decl anything that normally would be a plain C function, in case anything
//starts assuming the calling convention (libs/dlls/pleasent surprises).
extern "C"
{
	//these two go via ftol2.obj from the MSVC CRT, since any implementation
	//would have to guard the rounding mode anyway. ftol2 may or may not use SSE.
	inline double floor(double x) {return double(int(x));}
	inline float floorf(float x) {return float(int(x));}

	//inline x87/386 asm for CRT functions where possible, which will probably upset
	//the 64bit compiler. that's a todo, then.
	inline float sinf(float x)
	{
		float r;
		_asm
		{
			FLD x
			FSIN
			FSTP r
		};
		return r;
	}

	inline float cosf(float x)
	{
		float r;
		_asm
		{
			FLD x
			FCOS
			FSTP r
		};
		return r;
	}

	inline float fabsf(float x)
	{	
		float r;
		_asm
		{
			FLD x
			FABS
			FSTP r
		};
		return r;
	}

	inline float sqrtf(float x)
	{
		float r;
		_asm
		{
			FLD x
			FSQRT
			FSTP r
		};
		return r;
	}

	inline float tanf(float x)
	{
		//push x, and replace with cos
		//push y, replace with sin
		//replace sin(y) with div sin(x) / cos(x)
		//store to return & pop
		float r;
		_asm
		{
			FLD x
			FCOS
			FLD x
			FSIN
			FDIV st(0),st(1)
			FSTP r
		};
		return r;
	}

	//setjmp/longjmp functionality, this is experimental...
	#define _JBLEN  16
	#define _JBTYPE int
	typedef _JBTYPE jmp_buf[_JBLEN];
	/*
	 * Define jump buffer layout for x86 setjmp/longjmp.
	 */
	typedef struct __JUMP_BUFFER {
		unsigned long Ebp;
		unsigned long Ebx;				//4
		unsigned long Edi;				//8
		unsigned long Esi;				//12 - 0Ch
		unsigned long Esp;				//16 - 10h
		unsigned long Eip;				//20 - 14h
		unsigned long Registration;		//24 - 18h
		unsigned long TryLevel;			//28 - 1ch
		unsigned long Cookie;			//32 - 20h
		unsigned long UnwindFunc;		//36 - 24h
		unsigned long UnwindData[6];	//40
	} JumpBuffer;


	#define setjmp _setjmp
	#define longjmp _longjmp
	int __cdecl setjmp(jmp_buf _Buf);
	__declspec(noreturn) void __cdecl _longjmp(jmp_buf _Buf, int _Value);


	size_t strlen(const char* str);
};



#endif